<script lang="ts">
import { Component, Prop, Vue, Watch } from 'vue-facing-decorator';
import { addFavorite, removeFavorite } from '@/api/novel/novel';
import type { NovelListResponse } from '@/api/novel/list';
import type { ApiResponse } from '@/api/common';
import { ElMessage } from 'element-plus';
import UserLink from '@/pages/profile/component/UserLink.vue';

@Component({
  components: {
    UserLink,
  },
})
export default class NovelList extends Vue {
  @Prop() api!: (page: number) => Promise<ApiResponse<NovelListResponse>>

  total: number = 0;
  page: number = 1;
  novels: NovelListResponse['novels'] | null = [];
  @Watch('api')
  apiChangeHandler() {
    if (this.page !== 1) this.page = 1;
    else this.query();
  }
  @Watch('page')
  pageChangeHandler() {
    this.query();
  }

  queryLoading: symbol | null = null;
  async query() {
    const token = this.queryLoading = Symbol();
    this.novels = null;
    const resp = await this.api(this.page);
    if (token !== this.queryLoading) return;
    if (resp.error != null) {
      ElMessage({ type: 'error', message: resp.error });
      return;
    }
    this.total = resp.data.total;
    this.novels = resp.data.novels;
  }

  async setFavorite(novelId: number, isFavorite: boolean) {
    const resp = await (isFavorite ? addFavorite : removeFavorite)(novelId);
    if (resp.error != null) {
      ElMessage({ type: 'error', message: resp.error });
      return;
    }
    const novel = this.novels?.find(novel => novel.id === novelId);
    if (novel) novel.is_favorite = isFavorite;
  }

  mounted() {
    this.query();
  }
}
</script>
<template>
<div class="novel-list-container">
  <div class="novel-list">
    <div v-for="novel in novels" :key="novel.id" class="novel-list-item">
      <div class="novel-list-item-cover">
        <router-link :to="'/novel/' + novel.id">
          <img :src="novel.cover ? './api/image/' + novel.cover : './img/cover.png'" :title="novel.title" alt="" />
        </router-link>
        <el-button class="novel-list-item-fav novel-list-item-fav-off" text icon="el-icon-star" v-if="!novel.is_favorite" @click="setFavorite(novel.id, true)" />
        <el-button class="novel-list-item-fav novel-list-item-fav-on" text icon="el-icon-star-filled" v-else @click="setFavorite(novel.id, false)" />
      </div>
      <div class="novel-list-item-text">
        <router-link :to="'/novel/' + novel.id">
          <div class="novel-list-item-title" :title="novel.title">{{ novel.title }}</div>
        </router-link>
        <div class="novel-list-item-author">
          <user-link :user="novel.author" />
        </div>
      </div>
    </div>
  </div>
  <div class="novel-list-empty" v-if="novels && !novels.length">暂无小说</div>
  <div class="novel-list-pagination" v-if="total > 20">
    <el-pagination :current-page="page" :page-size="20" layout="prev, pager, next" :total="total" @current-change="page = $event" />
  </div>
</div>
</template>
<style scoped>
.novel-list-container {
  display: flow-root;
}

.novel-list {
  display: grid;
  gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
}

.tiny-mode .novel-list {
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}

.novel-list-item {
  display: flow-root;
  border: 1px solid var(--el-border-color-light);
  border-radius: var(--el-border-radius-base);
  overflow: hidden;
}

.novel-list-item:hover {
  box-shadow: var(--el-box-shadow-light);
}

.novel-list-item-cover {
  width: 100%;
  height: 0;
  padding-bottom: 141.42%;
  overflow: hidden;
  position: relative;
}

.novel-list-item-cover img {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  object-fit: cover;
  width: 100%;
  height: 100%;
}

.novel-list-item-fav {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 1;
  filter: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cfilter%20id%3D%22shadow-outline%22%3E%3CfeMorphology%20in%3D%22SourceAlpha%22%20operator%3D%22dilate%22%20radius%3D%221%22%20result%3D%22expanded%22%2F%3E%3CfeGaussianBlur%20stdDeviation%3D%222%22%20result%3D%22blurred%22%2F%3E%3CfeFlood%20flood-color%3D%22rgba(0%2C0%2C0%2C0.6)%22%20result%3D%22shadow-color%22%2F%3E%3CfeComposite%20in%3D%22shadow-color%22%20in2%3D%22blurred%22%20operator%3D%22in%22%20result%3D%22soft-shadow%22%2F%3E%3CfeComposite%20in%3D%22SourceGraphic%22%20in2%3D%22soft-shadow%22%20operator%3D%22over%22%2F%3E%3C%2Ffilter%3E%3C%2Fsvg%3E#shadow-outline');
}

.novel-list-item-fav-off {
  font-size: 24px;
  padding: 3px;
}

.novel-list-item:not(:hover) .novel-list-item-fav-off {
  visibility: hidden;
}

.novel-list-item-fav-on {
  font-size: 30px;
  padding: 0;
}

.novel-list-item-fav.novel-list-item-fav.novel-list-item-fav,
.novel-list-item-fav.novel-list-item-fav.novel-list-item-fav:hover {
  background: none;
  color: var(--el-color-warning);
}

.novel-list-item-text a {
  color: var(--el-text-color-primary);
}

.novel-list-item-title {
  margin: 10px;
  line-height: 25px;
  height: 50px;
  overflow: hidden;
  text-overflow: ellipsis;
}

.novel-list-item-author {
  margin: 10px;
  white-space: nowrap;
  overflow: hidden;
}

.novel-list-empty {
  margin: 100px 0;
  text-align: center;
  color: var(--el-text-color-secondary);
}

.novel-list-pagination {
  margin-top: 20px;
  margin-bottom: 20px;
  display: flex;
  justify-content: end;
}
</style>
